Preparing OPD Teacher by Merging LoRA weights in verl-omni
Follow the official tutorial for DiffusionOPD Trainer. This post briefly describes how to merge LoRA weights into base model through Diffusers.
Table of Contents
We take Stable Diffusion 3.5 Medium as an example. We first run the FlowGRPO trainer for stable diffusion, and it will generate a checkpoints folder (something like checkpoints/flow_grpo/sd35_medium_ocr_lora).
1. Step 1. Export LoRA from FSDP Checkpoint
There’s already a tool export_fsdp_lora_adapter() in verl_omni/utils/fsdp_utils.py that supports this. It directly aggregates lora_* tensors from FSDP checkpoints, and outputs standard PEFT format (adapter_config.json + adapter_model.safetensors).
$ python3 -c "
from verl_omni.utils.fsdp_utils import export_fsdp_lora_adapter
print(export_fsdp_lora_adapter(
'checkpoints/sd35_medium_ocr_distill/global_step_100/actor',
output_dir='checkpoints/sd35_ocr_lora_adapter',
base_model_name_or_path='stabilityai/stable-diffusion-3.5-medium', # or absolute path
))"
2. Step 2. Merging LoRA Weights and Save the New Model to Directory
I did meet some problems here1. The solution is that, we need to first edit the exported adapter_config.json in checkpoints/sd35_ocr_lora_adapter:
- set
task_typekey tonull - modify the term
"0"of keytarget_modulestoto_out.0
Then, we should merge the exported LoRA and the transformer part through PEFT.
- Copy the
stablilityai/stable-diffusion-3.5-mediumfolder tocheckpoints/sd35_ocr_merged_teacher - Run the following Python script to load the transformer part with
SD3Transformer2DModeland merge viaPeftModel.from_pretrainedthenmerge_and_unload.
import shutil, torch
from diffusers import SD3Transformer2DModel
from peft import PeftModel
base = "stabilityai/stable-diffusion-3.5-medium"
out = "checkpoints/sd35_ocr_merged_teacher"
lora = "checkpoints/sd35_ocr_lora_adapter"
tf = SD3Transformer2DModel.from_pretrained(
base,
subfolder="transformer",
torch_dtype=torch.bfloat16
)
tf = PeftModel.from_pretrained(tf, lora)
.merge_and_unload()
tf.save_pretrained(f"{out}/transformer") # Only overwrite the transformer part
You may verify by running sha256sum ....../transformer/diffusion_pytorch_model.safetensors.
And we’re done! We can then pass TEACHER_PATH=/path/to/sd35_ocr_merged_teacher as argument to run Diffusion OPD with Stable Diffusion 3.5 Medium with single teacher.
Footnotes:
In fact, at first time, I followed a wrong approach and exported an unmerged SD3.5Medium. How did I find this? Because I found that the reward@1 remained a very low level (around 0.22), fluctuated, and did not improve at all; as well as the actor/distill_kl_loss remained \(0\) over time. LMAO